;; The first four lines of this file were added by Dracula.
;; They tell DrScheme that this is a Dracula Modular ACL2 program.
;; Leave these lines unchanged so that DrScheme can properly load this file.
#reader(planet "reader.rkt" ("cce" "dracula.plt") "modular" "lang")
(require "iimage.lisp")
(require "icommon.lisp")
(require "mblur.lisp")
(require "isharpen.lisp")

(module MSharpen
  (include-book "avl-rational-keys" :dir :teachpacks)
  (include-book "list-utilities" :dir :teachpacks)
  (import iImage)
  (import iCommon)
  (import iBlur)
  
  ; Calculates the unsharp mask by substracting the RGB values of the blurred
  ; pixels from those of the original image. Then it sharpenes the original 
  ; image by adding the amount parameter multiplied by the unsharpmask color
  ; back to the original if the absolute value of the difference between the
  ; the pixel color in the original and the pixel color in the blurred image
  ; is greater than or equal to the threshold parameter.
  ; pre: norm - the tree of the original bitmap
  ;      blur - the tree of the blurred bitmap
  ;      threshold - integer value equal to the minimum differrence needed 
  ;                  to apply sharpening
  ;      amount - a rational number equal to the weight by which to sharpen
  ;      x - the column of the current pixel to check
  ;      y - the row of the current pixel to check
  ;      width - the width of the bitmap
  ;      height - the height of the bitmap
  ; post: a tree representing an unsharp mask of the original bitmap
  (defun processSharpen (norm blur x y threshold amount width height)
    (if (<= y height)
        (if (<= x width)
            (let* ((normRGB (getPixel norm x y))
                   (blurRGB (getPixel blur x y))
                   (normR (car normRGB))
                   (normG (cadr normRGB))
                   (normB (caddr normRGB))
                   (blurR (car blurRGB))
                   (blurG (cadr blurRGB))
                   (blurB (caddr blurRGB))
                   (UMR (if (>= (abs (- normR blurR)) threshold)
                            (+ (floor (* amount (- normR blurR)) 1) normR)
                            normR))
                   (UMG (if (>= (abs (- normG blurG)) threshold)
                            (+ (floor (* amount (- normG blurG)) 1) normG)
                            normG))
                   (UMB (if (>= (abs (- normB blurB)) threshold)
                            (+ (floor (* amount (- normB blurB)) 1) normB)
                            normB))
                   (newR (if (> UMR 255)
                             255
                             (if (< UMR 0)
                                 0
                                 UMR)))
                   (newG (if (> UMG 255)
                             255
                             (if (< UMG 0)
                                 0
                                 UMG)))
                   (newB (if (> UMB 255)
                             255
                             (if (< UMB 0)
                                 0
                                 UMB))))
              (processSharpen (insertPixel norm x y newR newG newB) blur 
                              (+ x 1) y threshold amount width height))
            (processSharpen norm blur 1 (+ y 1) threshold amount width height))
        norm))
                   
  ; Calls processSharpen to sharpen each pixel in a given bitmap. The sharpen command
  ; takes in two arguments <threshold> and <amount> respectively. If valid arguments
  ; are given, return a multiple-value consisting of the sharpened image and a
  ; success message respectively. Otherwise, return a multiple-value consisting of
  ; the original tree followed by an error message.
  (defun MainSharpen (tree args)
    (if (and (consp args) (= (len args) 2) (natp (car args)) (rationalp (cadr args))) 
        (mv (processSharpen tree (car (MainBlur tree (list 1))) 1 1 (car args)
                            (cadr args) (getWidth tree) (getHeight tree))
            (list "Sharpen successful"))
        (mv tree (list "Failed to Sharpen..."))))
      
  
  (export ISharpen))
